package com.apobates.jforum.grief.aurl.executor;

import com.apobates.jforum.grief.aurl.core.AUrlMeta;
import com.apobates.jforum.grief.aurl.core.AUrlMetaBuilder;
import com.apobates.jforum.grief.aurl.spring.StringUtils;
import com.apobates.jforum.grief.aurl.utils.defend.Predicates;
import com.apobates.jforum.grief.aurl.utils.defend.Assertion;
import com.apobates.jforum.grief.aurl.utils.defend.PredicateQueue;
import com.apobates.jforum.grief.aurl.utils.CurlyBraceSymbol;
import com.apobates.jforum.grief.aurl.utils.Pair;
import com.apobates.jforum.grief.aurl.utils.TriFunction;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Stream;

/**
 * 路径中占位符操作执行器
 */
public class PathParamExecutor extends AUrlMetaExecutor<Void>{
    private final AUrlMeta localIns;
    private final CurlyBraceSymbol urlSymbol;
    private final static BiFunction<String,String,String> PATH_SEG = (realUrl, host)->calcPathStr(realUrl, host);
    private final static TriFunction<String,String,String,String> REPLACE_VAR = (param, value, target)-> target.replace(String.format("{%s}", param), value);

    public PathParamExecutor(AUrlMeta rawMeta) {
        super(rawMeta);
        this.localIns = rawMeta.clone();
        this.urlSymbol = new CurlyBraceSymbol(localIns.toString());
    }

    @Override
    public Set<Void> getActionRecords() {
        return Collections.emptySet();
    }

    @Override
    public AUrlMetaBuilder getBuilder() {
        return localIns.toBuilder();
    }

    /**
     * 替换路径中的变量. 变量的包裹符号为:左大括号({)和右大括号(})
     * 适用于: 路径中只有一个占位符
     * @param param 路径中变量的占位符
     * @param value 占位符的替换值
     * @return
     */
    public String replace(String param, String value){
        PredicateQueue.<String>predicate(StringUtils::hasLength).asserts(Assertion.multi(param, value)).suspend();
        return REPLACE_VAR.apply(param, value, localIns.getPath());
    }

    /**
     * 替换路径中的变量. 变量的包裹符号为:左大括号({)和右大括号(})
     * 适用于: 路径中只有两个占位符
     * @param param1 路径中变量的占位符1
     * @param value1 占位符1的替换值
     * @param param2 路径中变量的占位符2
     * @param value2 占位符2的替换值
     * @return
     */
    public String replace(String param1, String value1, String param2, String value2){
        PredicateQueue.<String>predicate(StringUtils::hasLength).asserts(Assertion.multi(param1, value2, param2, value2)).suspend();
        return REPLACE_VAR.andThen((rs)->rs.replace(String.format("{%s}", param2), value2)).apply(param1, value1, localIns.getPath());
    }

    /**
     * 替换路径中的变量. 变量的包裹符号为:左大括号({)和右大括号(})
     * 适用于: 路径中只有三个占位符
     * @param param1 路径中变量的占位符1
     * @param value1 占位符1的替换值
     * @param param2 路径中变量的占位符2
     * @param value2 占位符2的替换值
     * @param param3 路径中变量的占位符3
     * @param value3 占位符3的替换值
     * @return
     */
    public String replace(String param1, String value1, String param2, String value2, String param3, String value3){
        PredicateQueue.<String>predicate(StringUtils::hasLength).asserts(Assertion.multi(param1, value2, param2, value2, param3, value3)).suspend();
        return REPLACE_VAR.apply(param3, value3, this.replace(param1, value1, param2, value2));
    }

    /**
     * 替换路径中的变量. 变量的包裹符号为:左大括号({)和右大括号(})
     * 适用于: 路径中有三个以上的占位符
     * @param paramValueMap key=路径中变量的占位符, value=占位符的替换值
     * @return
     */
    public String replace(Map<String,String> paramValueMap){
        PredicateQueue.require().notEmpty().asserts(Assertion.single(paramValueMap)).suspend();
        String realUrl = urlSymbol.replace(paramValueMap);
        return PATH_SEG.apply(realUrl, localIns.getHost());
    }

    /**
     * 替换路径中的变量. 变量的包裹符号为:左大括号({)和右大括号(})
     * 适用于: 路径中有三个以上的占位符
     * @param paramValuePairList left=占位符, right=占位符的替换值
     * @return
     */
    public String replace(Collection<Pair<String,String>> paramValuePairList){
        PredicateQueue.require().notEmpty().asserts(Assertion.single(paramValuePairList)).suspend();
        String realUrl = urlSymbol.replace(paramValuePairList);
        return PATH_SEG.apply(realUrl, localIns.getHost());
    }

    /**
     * 使用占位符定义解压实例
     * @param paramValueMap 占位符定义Map, key=占位符, value=占位符的替换值
     * @return
     */
    public AUrlMeta extract(Map<String,String> paramValueMap){
        PredicateQueue.require().notEmpty().asserts(Assertion.single(paramValueMap)).suspend();
        return this.getBuilder().templateByMap(paramValueMap);
    }

    /**
     * 使用占位符定义解压实例至字符串
     * @param paramValueMap 占位符定义Map, key=占位符, value=占位符的替换值
     * @return
     */
    public String extractToString(Map<String,String> paramValueMap){
        PredicateQueue.require().notEmpty().asserts(Assertion.single(paramValueMap)).suspend();
        return urlSymbol.replace(paramValueMap);
    }
    /**
     * 使用占位符定义解压实例
     * @param instance javaBean实例。要求:占位符可以通过getter方法取得值
     * @return
     * @param <T>
     */
    public <T> AUrlMeta extract(T instance){
        PredicateQueue.require().asserts(Assertion.single(instance)).suspend();
        return this.getBuilder().templateByObj(instance);
    }

    /**
     * 使用占位符定义解压实例至字符串
     * @param instance javaBean实例。要求:占位符可以通过getter方法取得值
     * @return
     * @param <T>
     */
    public <T> String extractToString(T instance) {
        PredicateQueue.require().asserts(Assertion.single(instance)).suspend();
        return urlSymbol.replace(instance);
    }
    /**
     * 使用多个占位符定义解压多个实例
     * @param paramValueMapes 占位符定义Map, key=占位符, value=占位符的替换值
     * @return
     */
    public Stream<AUrlMeta> extractByMap(Collection<Map<String,String>> paramValueMapes){
        if(paramValueMapes.isEmpty()){
            return Stream.empty();
        }
        return paramValueMapes.stream().map(mapIns->this.getBuilder().templateByMap(mapIns));
    }

    /**
     * 使用多个占位符定义解压至实例字符串
     * @param paramValueMapes 占位符定义Map, key=占位符, value=占位符的替换值
     * @return
     */
    public Stream<String> extractByMapToString(Collection<Map<String,String>> paramValueMapes){
        if(paramValueMapes.isEmpty()){
            return Stream.empty();
        }
        return paramValueMapes.stream().map(map->urlSymbol.replace(map));
    }
    /**
     * 使用多个javaBean实例解压多个实例
     * @param collection javaBean实例集合。要求:占位符可以通过getter方法取得值
     * @return
     * @param <T>
     */
    public <T> Stream<AUrlMeta> extractByObject(Collection<T> collection){
        PredicateQueue.require().notEmpty().asserts(Assertion.single(collection)).suspend();
        return collection.stream().map(mapIns->this.getBuilder().templateByObj(mapIns));
    }

    /**
     * 使用多个javaBean实例解压至实例字符串
     * @param collection javaBean实例集合。要求:占位符可以通过getter方法取得值
     * @return
     * @param <T>
     */
    public <T> Stream<String> extractByObjectToString(Collection<T> collection){
        PredicateQueue.require().notEmpty().asserts(Assertion.single(collection)).suspend();
        return collection.stream().map(ins->urlSymbol.replace(ins));
    }

    private static String calcPathStr(String url, String domain){
        String b = url.substring(url.indexOf(domain));
        String c = b.substring(b.indexOf("/"));

        return c;
    }
}
